/** 【文件说明】：请求类
 *  【使用例子】：
 
    import service from './path-to-your-request-class';
  //发送 GET 请求
  service.get('/api/data', {
    params: { id: 123, type: 'user' },
    showLoading: true,
    needToken: true
  }).then(response => {
    console.log('Response:', response);
  }).catch(error => {
    console.error('Error:', error);
  });

  //发送 POST 请求
  const postData = {
    name: 'John Doe',
    email: 'john.doe@example.com'
  };
  service.post('/api/users', postData, {
    showLoading: true,
    needToken: true,
    repeatSubmit: false
  }).then(response => {
    console.log('Response:', response);
  }).catch(error => {
    console.error('Error:', error);
  });

  //下载文件
  const params = { reportType: 'sales' };
  download('/api/reports/download', params, 'report.csv', {
    showLoading: true,
    needToken: true
  }).then(() => {
    console.log('File downloaded successfully.');
  }).catch(error => {
    console.error('Download failed:', error);
  });
    
 */

import axios, { AxiosRequestConfig, AxiosResponse, AxiosError, AxiosRequestHeaders } from 'axios';
import { ElNotification, ElMessageBox, ElMessage, ElLoading } from 'element-plus';
import { saveAs } from 'file-saver';
import cache from '../plugins/cache'
import { ref } from 'vue';

// 定义 errorCode 的类型
interface ErrorCodeMap {
  [key: string]: string;
}

// 错误代码映射
const errorCode: ErrorCodeMap = {
  '401': '认证失败，无法访问系统资源',
  '403': '当前操作没有权限',
  '404': '访问资源不存在',
  'default': '系统未知错误，请反馈给管理员'
};

// 是否显示重新登录
export let isRelogin = { show: false };

// 获取 token
function getToken() {
  return localStorage.getItem('token');
}

// Blob 验证函数
function blobValidate(data: any) {
  return data.type !== 'application/json';
}

const loadingInstance = ElLoading.service({
  fullscreen: true,
  text: '正在加载...',
});

// 将参数转换为 URL 编码的字符串
export function tansParams(params: any): string {
  let result = '';
  for (const propName of Object.keys(params)) {
    const value = params[propName];
    var part = encodeURIComponent(propName) + "=";
    if (value !== null && value !== "" && typeof value !== "undefined") {
      if (typeof value === 'object') {
        for (const key of Object.keys(value)) {
          if (value[key] !== null && value[key] !== "" && typeof value[key] !== 'undefined') {
            let paramsKey = propName + '[' + key + ']';
            var subPart = encodeURIComponent(paramsKey) + "=";
            result += subPart + encodeURIComponent(value[key]) + "&";
          }
        }
      } else {
        result += part + encodeURIComponent(value) + "&";
      }
    }
  }
  return result ? result.slice(0, -1) : result; // 去掉最后一个多余的 &
}

// 请求配置接口
interface RequestConfig extends AxiosRequestConfig {
  headers: AxiosRequestHeaders; // 确保 headers 是 AxiosRequestHeaders 类型，并且是非可选的
  showLoading?: boolean; // 可选配置，用于控制是否显示加载动画
  needToken?: boolean; // 可选配置，用于控制是否需要携带 token
  repeatSubmit?: boolean;
}

// 创建axios实例
const service = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  } as AxiosRequestHeaders
});

// request拦截器
service.interceptors.request.use(
  (config: RequestConfig) => {
    // 是否需要设置 token
    const isToken = config.needToken !== false;
    // 是否需要防止数据重复提交，默认为 false
    const isRepeatSubmit = config.repeatSubmit !== undefined ? config.repeatSubmit : false;

    if (isToken && getToken()) {
      (config.headers as AxiosRequestHeaders)['Authorization'] = 'Bearer ' + getToken();
    }

    // get请求映射params参数
    if (config.method?.toLowerCase() === 'get' && config.params) {
      let url = config.url + '?' + tansParams(config.params);
      config.params = {};
      config.url = url;
    }
    if (!isRepeatSubmit && (config.method?.toLowerCase() == 'post' || config.method?.toLowerCase() == 'put')) {
      const requestObj = {
        url: config.url,
        data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
        time: new Date().getTime()
      };
      const sessionObj = cache.session.getJSON('sessionObj');
      if (!sessionObj) {
        cache.session.setJSON('sessionObj', requestObj);
      } else {
        const s_url = sessionObj.url;
        const s_data = sessionObj.data;
        const s_time = sessionObj.time;
        const interval = 1000; // 间隔时间(ms)，小于此时间视为重复提交
        if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
          const message = '数据正在处理，请勿重复提交';
          console.warn(`[${s_url}]: ` + message);
          return Promise.reject(new Error(message));
        } else {
          cache.session.setJSON('sessionObj', requestObj);
        }
      }
    }

    // 显示加载动画
    if (config.showLoading) {
      console.log("request.ts显示加载动画");
      loadingInstance.fullscreen = ref<boolean>(true);
      loadingInstance.setText('正在加载...');
    }

    return config;
  },
  (error: AxiosError) => {
    console.error(error);
    return Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  (res: AxiosResponse) => {
    const code = res.data.code || 200;
    const msg = errorCode[code] || res.data.msg || errorCode['default'];

    // 二进制数据则直接返回
    if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
      return res.data;
    }

    // 关闭加载动画
    if (loadingInstance) {
      loadingInstance.close();
    }

    if (code === 401) {
      if (!isRelogin.show) {
        isRelogin.show = true;
        ElMessageBox.confirm('登录状态已过期，您可以继续留在该页面，或者重新登录', '系统提示', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          isRelogin.show = false;
          // useUserStore().logOut().then(() => {
          //   location.href = '/index';
          // });
        }).catch(() => {
          isRelogin.show = false;
        });
      }
      return Promise.reject('无效的会话，或者会话已过期，请重新登录。');
    } else if (code === 500) {
      ElMessage({ message: msg, type: 'error' });
      return Promise.reject(new Error(msg));
    } else if (code === 601) {
      ElMessage({ message: msg, type: 'warning' });
      return Promise.reject(new Error(msg));
    } else if (code !== 200) {
      ElNotification.error({ title: msg });
      return Promise.reject('error');
    } else {
      return Promise.resolve(res.data);
    }
  },
  (error: AxiosError) => {
    // 关闭加载动画
    if (error.config && loadingInstance) {
      loadingInstance.close();
    }

    let { message } = error;
    if (message === "Network Error") {
      message = "后端接口连接异常";
    } else if (message.includes("timeout")) {
      message = "系统接口请求超时";
    } else if (message.includes("Request failed with status code")) {
      message = "系统接口" + message.substr(message.length - 3) + "异常";
    }
    ElMessage({ message: message, type: 'error', duration: 5 * 1000 });
    return Promise.reject(error);
  }
);

// 通用下载方法
export function download(url: string, params: any, filename: string, config: RequestConfig) {
  loadingInstance.setText("正在下载数据，请稍候");
  loadingInstance.background = ref<string>("rgba(0, 0, 0, 0.7)");

  // 合并默认的 Content-Type 头和传入的配置中的 headers
  return service.post(url, params, {
    ...config,
    headers: {
      ...config.headers, // 保留原始 headers
      'Content-Type': 'application/x-www-form-urlencoded' // 添加或覆盖 Content-Type
    },
    responseType: 'blob', // 设置响应类型为 blob 以便处理二进制文件
    transformRequest: [(params) => tansParams(params)],// 应用参数转换函数

  }).then(async (response: AxiosResponse) => {
    const data = response.data;
    const isBlob = blobValidate(data);
    if (isBlob) {
      const blob = new Blob([data]);
      saveAs(blob, filename);
    } else {
      const resText = await data.text();
      const rspObj = JSON.parse(resText);
      const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'];
      ElMessage.error(errMsg);
    }
    loadingInstance.close();
  }).catch((r) => {
    console.error(r);
    ElMessage.error('下载文件出现错误，请联系管理员！');
    loadingInstance.close();
  });
}

export default service;